package com.gadarts.parashoot;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import com.example.parashoot.R;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

@SuppressLint("ViewConstructor")
public class GameView extends SurfaceView {

	protected float ratioX, ratioY;// Game ratio between XHDPI to current DPI.
	private GameModel model;
	private GameLoopThread gameLoopThread;
	private SurfaceHolder holder;
	private SparseArray<PointF> mActivePointers;// The pointers on the screen.
	private Bitmap currentBG;// The current selected background image.
	private ArrayList<Sprite> sprites;
	private boolean init;// Indicates whether the view has initialized.
	private boolean gfxReady;// Indicates whether the GFX is fully loaded.

	public GameView(Context context, GameModel model) {
		super(context);
		this.model = model;
		gameLoopThread = new GameLoopThread(this, this.model);
		holder = getHolder();
		holder.addCallback(new Callback() {
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
			}

			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				gameLoopThread.setRunning(true);
				gameLoopThread.start();
			}

			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				gameLoopThread.setRunning(false);
			}
		});
		mActivePointers = new SparseArray<PointF>();
	}

	private void loadGFX() {// Loads all the GFX file into the game.
		sprites = new ArrayList<Sprite>();
		final R.drawable drawableResources = new R.drawable();
		final Class<R.drawable> c = R.drawable.class;
		final Field[] fields = c.getDeclaredFields();

		currentBG = loadImage(R.drawable.desertday, getWidth(), getHeight());

		ratioX = (float) (getWidth()) / (float) (currentBG.getWidth());
		ratioY = (float) (getHeight()) / (float) (currentBG.getHeight());

		// Put all images into the sprites list.
		for (int i = 0, max = fields.length; i < max; i++) {
			final int resourceId;
			try {
				resourceId = fields[i].getInt(drawableResources);
				String imageName2 = getResources().getResourceName(resourceId)
						.split("/")[1];
				String imageName = imageName2.replaceAll("[^A-Za-z]", "");
				Bitmap bitmap = loadImage(resourceId);
				
				if (sprites.size() > 0) {
					// Check whether the current image is needed to be added to
					// an existent sprite or a new one.
					for (int j = 0; j < sprites.size(); j++) {
						Sprite currentSprite = sprites.get(j);
						if (currentSprite.getName().equals(imageName)) {
							currentSprite.add(bitmap);
							break;
						}
						if (j == (sprites.size() - 1)) {
							Sprite sprite = new Sprite();
							sprite.add(bitmap);
							sprite.setName(imageName);
							sprites.add(sprite);
							break;
						}
					}
				} else {
					Sprite sprite = new Sprite(imageName, bitmap);
					sprites.add(sprite);
				}

			} catch (Exception e) {
				continue;
			}
		}
		gfxReady = true;
	}

	private Bitmap loadImage(int resourceId, int width, int height) {
		Bitmap bitmap = BitmapFactory
				.decodeResource(getResources(), resourceId);
		if (width > 0 && height > 0)
			bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
		return bitmap;
	}

	private Bitmap loadImage(int resourceId) {
		return loadImage(resourceId, -1, -1);
	}

	public void drawGFX(Canvas canvas) {// Draw the current game's screen.
		if (init == false) {
			loadGFX();// Loads all the GFX file into the game.
			init = true;
		}
		canvas.drawBitmap(currentBG, 0, 0, null);
		GameObject currentObject;
		List<GameObject> drawList = model.drawList;
		// Draw from lowest depth to highest.
		for (int i = 0; i < drawList.size(); i++) {
			currentObject = drawList.get(i);
			if (currentObject.fitFrameToDirection())
				canvas.drawBitmap(currentObject.getImage(),
						currentObject.getMatrix(), null);
			else
				canvas.drawBitmap(currentObject.getImage(),
						currentObject.getX(), currentObject.getY(), null);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {// Click events.
		synchronized (getHolder()) {
			// get pointer index from the event object
			int pointerIndex = event.getActionIndex();
			// get pointer ID
			int pointerId = event.getPointerId(pointerIndex);
			// get masked (not specific to a pointer) action
			int maskedAction = event.getActionMasked();
			switch (maskedAction) {
			case MotionEvent.ACTION_DOWN:
			case MotionEvent.ACTION_POINTER_DOWN: {// When pressing.
				// We have a new pointer. Lets add it to the list of pointers.
				PointF f = new PointF();// A Pointer.
				f.x = event.getX(pointerIndex);
				f.y = event.getY(pointerIndex);
				mActivePointers.put(pointerId, f);
				model.actionDownEvent(f.x, f.y);
				break;
			}
			case MotionEvent.ACTION_MOVE: {
				for (int size = event.getPointerCount(), i = 0; i < size; i++) {
					PointF point = mActivePointers.get(event.getPointerId(i));
					if (point != null) {
						point.x = event.getX(pointerIndex);
						point.y = event.getY(pointerIndex);
						model.actionMoveEvent(point.x, point.y);
						break;
					}
				}
				break;
			}
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_POINTER_UP: {// When finger lift up.
				for (int size = event.getPointerCount(), i = 0; i < size; i++) {
					PointF point = mActivePointers.get(event.getPointerId(i));
					if (point != null) {
						model.actionReleaseEvent(event.getX(pointerIndex),
								event.getY(pointerIndex));
						mActivePointers.remove(pointerIndex);
					}
				}
				break;
			}
			}
		}
		invalidate();
		return true;
	}

	public Sprite getSprite(String name) {
		for (int i = 0; i < sprites.size(); i++) {
			Sprite currentSprite = sprites.get(i);
			if (currentSprite.getName().equals(name))
				return currentSprite;
		}
		return null;
	}
	
	public Sprite getSpriteWithReverse(String name) {
		for (int i = 0; i < sprites.size(); i++) {
			Sprite currentSprite = sprites.get(i);
			if (currentSprite.getName().equals(name))
				return currentSprite.addReverse();
		}
		return null;
	}

	public Bitmap getImage(String name) {
		Sprite sprite = getSprite(name);
		if (sprite != null) {
			return sprite.get(0);
		}
		return null;
	}

	public boolean isGfxLoaded() {
		return gfxReady;
	}
}
